import React, { useState } from 'react';
import { useCookies } from 'react-cookie';
import { Controller, useForm } from 'react-hook-form';
import { ErrorMessage } from '@hookform/error-message';
import {
  Box,
  Datepicker,
  FormStatusMessage,
  Grid,
  GridItem,
  Input,
  MainColorType,
  NumberInput,
  Radio,
  Text,
} from '@nova-hf/ui';
import { emailValidate, objectToQuery } from 'beta/utils/helpers';
import { useTranslation } from 'beta/utils/i18n';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
import {
  InitiatePayerChangeInput,
  useAddCustomerMutation,
  useInitiatePayerChangeMutation,
  useLegalEntitiesLazyQuery,
  useUpdateCustomerMutation,
  WhenToApply,
} from 'typings/graphql';

import { SettingsButtons } from '../components/SettingsButtons';

const { publicRuntimeConfig } = getConfig();
const redirectURL = publicRuntimeConfig.NOVA_WEB_URL ?? '';

type NewPayerInput = {
  nationalId: string;
  newPayerId: string;
  name: string;
  email?: string;
  date?: Date;
  whenToApply: WhenToApply;
};

type ChangePaymentFormProps = {
  payerNationalId?: string;
  color: MainColorType;
  contractId?: string;
  contractIds?: string[];
  customerId?: string;
};

export const ChangePayerForm = ({
  payerNationalId,
  color,
  contractId,
  contractIds,
  customerId,
}: ChangePaymentFormProps) => {
  const { t } = useTranslation('stillingar');
  const router = useRouter();
  const [, setCookie] = useCookies(['returnUrl']);
  const [nationalIdToCheck, setNationalIdToCheck] = useState('');

  const {
    control,
    getValues,
    setValue,
    setError,
    reset,
    clearErrors,
    handleSubmit,
    trigger,
    watch,
    formState: { isValid },
  } = useForm<NewPayerInput>({
    defaultValues: {
      nationalId: '',
      newPayerId: '',
      name: '',
      email: '',
      date: new Date(),
      whenToApply: WhenToApply.Immediate,
    },
    delayError: 500,
    mode: 'onChange',
  });

  const { whenToApply, email, newPayerId, nationalId } = watch();

  const [updateCustomerInfo, { loading: loadingUpdateCustomer }] = useUpdateCustomerMutation();

  const [initatePayerChange, { loading: loadingPayerChange, error: initatePayerChangeError }] =
    useInitiatePayerChangeMutation({
      onCompleted: async (data) => {
        if (data?.initiatePayerChange?.cartId) {
          const origin = window.location.origin;
          const finalSlashIndex = router.asPath.lastIndexOf('/'); //remove "stillingar" from path
          const previousPath = router.asPath.slice(0, finalSlashIndex);

          const returnUrl = `${origin}${previousPath}`;
          const expirationTime = new Date(Date.now() + 1 * 60 * 60 * 1000); // cookie expires in 1 hour
          setCookie('returnUrl', returnUrl, {
            path: '/',
            expires: expirationTime,
            domain: 'nova.is',
            sameSite: 'none',
            secure: true,
          });

          const redirectQueryParam = objectToQuery({
            cartId: data.initiatePayerChange.cartId,
            customerId: customerId ?? '',
            nationalId: nationalId,
          });

          if (legalEntityData?.legalEntities?.customer?.email !== email) {
            await updateCustomerInfo({ variables: { input: { customerId: newPayerId, email } } });
          }
          window.location.href = `${redirectURL}/audkenning/staff?redirect=/barinn/fiber-greidsla?${redirectQueryParam}`;
        }
      },
    });
  const [addCustomer, { loading: loadingAddCustomer }] = useAddCustomerMutation();
  const [getLegalEntity, { loading: loadingGetLegalEntity, data: legalEntityData }] =
    useLegalEntitiesLazyQuery({
      fetchPolicy: 'network-only',
      onCompleted: async (data) => {
        const nationalId = getValues('nationalId');
        if (data) {
          if (data.legalEntities?.isChild) {
            setError('nationalId', {
              message: t('payerSettings.errors.isChild'),
            });
            return;
          }
          if (!data.legalEntities?.isCustomer) {
            try {
              const { data: addCustomerData } = await addCustomer({
                variables: {
                  input: {
                    nationalId,
                  },
                },
              });
              if (addCustomerData?.addCustomer.customer.id) {
                const id = addCustomerData.addCustomer.customer.id;
                if (id) {
                  setValue('newPayerId', id);
                }
              }
            } catch (error) {
              if (error instanceof Error) {
                setError('nationalId', {
                  message: t('payerSettings.errors.failedToFetchLegalEntity'),
                });
                setValue('name', '');
                return;
              }
            }
          }
          if (data.legalEntities?.name) {
            setValue('name', data.legalEntities?.name);
            setValue('email', data.legalEntities.customer?.email ?? '');
            if (data.legalEntities.isCustomer) {
              setValue('newPayerId', data.legalEntities.customer?.id ?? '');
              if (payerNationalId && nationalId === payerNationalId) {
                setError('nationalId', {
                  message: t('payerSettings.errors.customerIsTheSame'),
                });
              }
            }
          }
          trigger();
        }
      },
      onError(error) {
        if (error instanceof Error) {
          setError('nationalId', {
            message: t('payerSettings.errors.notFound'),
          });
          setValue('name', '');
          setValue('email', '');
        }
      },
    });

  const validateNationaldId = (value: string) => {
    if (value.trim().length === 10) {
      if (nationalIdToCheck !== value) {
        setNationalIdToCheck(value);
        getLegalEntity({ variables: { input: { nationalId: value } } });
      }
    } else {
      setValue('name', '');
      setValue('email', '');
      clearErrors();
      if (nationalIdToCheck !== '') {
        setNationalIdToCheck('');
      }
    }
    return true;
  };

  const onSubmit = (newPayerForm: NewPayerInput) => {
    if (contractId || contractIds) {
      const initatePayerChangePayload: InitiatePayerChangeInput = {
        contractIds: contractId ? [contractId] : contractIds,
        newPayerId: newPayerForm.newPayerId,
        effectiveDate: newPayerForm.date,
        whenToApply: newPayerForm.whenToApply,
      };
      initatePayerChange({
        variables: {
          input: {
            ...initatePayerChangePayload,
          },
        },
      });
    }
  };

  return (
    <Box>
      <Grid gridTemplate={{ sm: 4, md: 8 }}>
        <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
          <Text color="black100" variant="pLargeBold" marginTop={5}>
            {t('payerSettings.newPayerTitle')}
          </Text>
        </GridItem>

        <GridItem gridColumn={{ sm: 'span4' }}>
          <Controller
            name="nationalId"
            control={control}
            rules={{
              required: t('payerSettings.errors.nationalIdMissing').toString(),
              validate: {
                nationalIdValidation: (value) => validateNationaldId(value),
              },
            }}
            render={({ field, formState: { errors } }) => {
              const { value, name, ref, onChange } = field;
              return (
                <>
                  <NumberInput
                    id="nationalIdInput"
                    numberType="nationalId"
                    ref={ref}
                    name={name}
                    label={t('payerSettings.payerNationaIdLabel')}
                    isBold={false}
                    value={value}
                    disabled={loadingPayerChange}
                    onChange={(val) => onChange(val)}
                  />
                  <ErrorMessage
                    errors={errors}
                    name={name}
                    render={({ message }) => {
                      return <FormStatusMessage message={message} status="error" />;
                    }}
                  />
                  {(loadingAddCustomer || loadingGetLegalEntity) && !errors.nationalId && (
                    <FormStatusMessage message={t('payerSettings.loadingName')} status="loading" />
                  )}
                </>
              );
            }}
          />
        </GridItem>
        <GridItem gridColumn={{ sm: 'span4' }}>
          <Controller
            name="name"
            control={control}
            render={({ field }) => {
              return (
                <Input
                  id="name"
                  label={t('payerSettings.payerNameLabel')}
                  disabled
                  isBold={false}
                  {...field}
                />
              );
            }}
          />
        </GridItem>
        <GridItem gridColumn={{ sm: 'span4' }}>
          <Controller
            name="email"
            control={control}
            rules={{
              required: t('payerSettings.errors.eamilMissing').toString(),
              validate: {
                email: (value) => {
                  const errorMessage = t('payerSettings.errors.emailNotValid') || '';
                  return emailValidate(value ?? '') ? true : errorMessage;
                },
              },
            }}
            render={({ field, formState: { errors } }) => {
              return (
                <>
                  <Input
                    id="emailInput"
                    label={t('payerSettings.emailLabel')}
                    isBold={false}
                    autoComplete="off"
                    {...field}
                  />
                  <ErrorMessage
                    errors={errors}
                    name={field.name}
                    render={({ message }) => <FormStatusMessage message={message} status="error" />}
                  />
                </>
              );
            }}
          />
        </GridItem>

        <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
          <Text color="black100" variant="pLargeBold" marginTop={4}>
            {t('payerSettings.whenToApplyTitle')}
          </Text>
        </GridItem>
        <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
          <Controller
            name="whenToApply"
            control={control}
            rules={{ required: true }}
            render={({ field }) => {
              const { value, onChange } = field;
              return (
                <Box color="black100" display="flex" gap={5}>
                  <Radio
                    isChecked={value === WhenToApply.Immediate}
                    value={t('payerSettings.immediateLabel').toString()}
                    color={color}
                    onChange={() => onChange(WhenToApply.Immediate)}
                    isDisabled={loadingPayerChange}
                  />
                  <Radio
                    isChecked={value === WhenToApply.StartOfNextCycle}
                    value={t('payerSettings.startOfNextCycleLabel').toString()}
                    color={color}
                    onChange={() => onChange(WhenToApply.StartOfNextCycle)}
                    isDisabled={loadingPayerChange}
                  />
                  <Radio
                    isChecked={value === WhenToApply.CustomDate}
                    value={t('payerSettings.customDateLabel').toString()}
                    color={color}
                    onChange={() => onChange(WhenToApply.CustomDate)}
                    isDisabled={loadingPayerChange}
                  />
                </Box>
              );
            }}
          />
        </GridItem>

        {whenToApply === WhenToApply.CustomDate && (
          <>
            <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
              <Text variant="pLargeBold" marginTop={4}>
                {t('payerSettings.customDateTitle')}
              </Text>
            </GridItem>
            <GridItem gridColumn={{ sm: 'span4', md: 'span4' }}>
              <Controller
                name="date"
                control={control}
                rules={{ required: true }}
                render={({ field }) => {
                  const { value, onChange } = field;
                  return (
                    <Box display="flex" width="100%">
                      <Datepicker
                        inputId="datepicker"
                        inputName="datepicker"
                        color="black100"
                        selected={value}
                        minDate={new Date()}
                        onSelect={(date: Date) => onChange(date)}
                        disabled={loadingPayerChange}
                      />
                    </Box>
                  );
                }}
              />
            </GridItem>
          </>
        )}
        {initatePayerChangeError && (
          <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
            <FormStatusMessage
              message={t('payerSettings.errors.couldNotInitiatePayerChange')}
              status="error"
            />
          </GridItem>
        )}
        <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
          <SettingsButtons
            cancelButton={{
              text: t('payerSettings.buttons.cancel'),
              colorScheme: 'white',
              onClick: () => {
                reset();
                clearErrors();
              },
              isDisabled: loadingPayerChange,
            }}
            confirmButton={{
              text: t('payerSettings.buttons.confirm'),
              colorScheme: color,
              isDisabled: !isValid || loadingAddCustomer || loadingGetLegalEntity || !newPayerId,
              onClick: handleSubmit(onSubmit),
              isLoading: loadingPayerChange || loadingUpdateCustomer,
              icon: 'longArrowRight',
            }}
          />
        </GridItem>
      </Grid>
    </Box>
  );
};
